﻿using GDI_应用案例.Pages.Controls._3D;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Numerics;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace GDI_应用案例.Pages.Controls
{
    public unsafe class Rect3D : Draw3DBase
    {
        private RectangleF3D _rectangleF3D;
        private PointF* _cubePointsPtr;// 8个顶点的2d坐标
        private const int _cubePointsPtrSize = 8;
        private PointF[] _points = new PointF[24];// 12条线的端点

        private bool _isDragging = false; // 是否正在拖动
        private Point _lastMousePosition; // 上次鼠标位置
        private Point3D* _point3DPtr;// 8个顶点
        private const int _point3DPtrSize = 8;
        private float _scale = 1.0f; // 初始缩放比例为 1
        private float _scaleFactor = 0.1f; // 每次滚动的缩放比例变化量
        private RectangleF _bounds = RectangleF.Empty;

        public Rect3D(RectangleF3D rectangleF3D)
            : this(new Point3D(0, 0,0), rectangleF3D)
        {
        }
        public Rect3D(Point3D viewpointPosition, RectangleF3D rectangleF3D)
        {
            base.ViewpointPosition = viewpointPosition;
            _rectangleF3D = rectangleF3D;
            Distance = 100;
            _point3DPtr = AllocateT<Point3D>(_point3DPtrSize);
            _cubePointsPtr = AllocateT<PointF>(_cubePointsPtrSize);
            RotationScale = 0.01f;
        }
        public float Scale
        {
            get => _scale;
            set
            {
                var temp = Math.Max(0.1f, value);
                _scale = temp;
            }
        }
        public float ScaleFactor
        {
            get => _scaleFactor;
            set
            {
                var temp = Math.Max(0, value);
                _scaleFactor = temp;
            }
        }
        public override RectangleF Bounds
        {
            get
            {
                fixed (RectangleF* p = &_bounds)
                    ToRectangleF(p, Distance);
                return _bounds;
            }
        }
        public float RotationScale { get; set; }
        public override void Draw(Graphics g, Pen pen)
        {
            _rectangleF3D.ToPoint3D(_point3DPtr);
            UpdateCenter();
            Draw(g, pen, _point3DPtr, _point3DPtrSize);

            
        }
        private void Draw(Graphics g, Pen pen, Point3D* points, int size)
        {
            for (int i = 0; i < size; i++)
            {
                // 平移到原点
                Point3D* p = points + i;
                p->X -= _center.X;
                p->Y -= _center.Y;
                p->Z -= _center.Z;
                // 应用缩放
                p->X *= _scale;
                p->Y *= _scale;
                p->Z *= _scale;
                // 应用矩阵变换
                fixed (Matrix4x4* m = &_rotationMatrix)
                    TransformPoint(p, m);
                // 平移回原位置
                p->X += _center.X;
                p->Y += _center.Y;
                p->Z += _center.Z;
                fixed (Point3D* vp = &ViewpointPosition)
                    (points + i)->ToPointF(_cubePointsPtr + i, Distance, vp);
            }
            Draw(g, pen, _cubePointsPtr, _edgescube, 12);
        }
        private void Draw(Graphics g, Pen pen, PointF* pf, int[,] edges, int size)
        {
            int index = 0;
            for (int i = 0; i < size; i++)
            {
                _points[index++] = *(pf + edges[i, 0]);
                _points[index++] = *(pf + edges[i, 1]);
            }
            g.DrawLines(pen, _points);
        }
        public override void OnMouseDown(MouseEventArgs e)
        {
            if (IsMouseInRect(e.Location))
            {
                _isDragging = true;
                _lastMousePosition = e.Location;
            }
            else
            {
                _isDragging = false;
            }
        }
        public override void OnMouseUp(MouseEventArgs e)
        {
            _isDragging = false;
        }
        public override void OnMouseLeave(EventArgs e)
        {
            _isDragging = false;
        }
        public override void OnMouseWheel(MouseEventArgs e)
        {
            if (e.Delta > 0) // 滚轮向上滚动，放大
                _scale += _scaleFactor;
            else if (e.Delta < 0) // 滚轮向下滚动，缩小
                _scale -= _scaleFactor;
            // 限制最小缩放比例，避免缩小到 0 或负数
            _scale = Math.Max(0.1f, _scale);

            //PointF pt = ViewpointPosition;
            //PointF* p = &pt;
            //p->X*=_scale;
            //p->Y*=_scale;
            //base.ViewpointPosition = *p;
        }
        public override void OnMouseMove(MouseEventArgs e)
        {
            if (!_isDragging) return;
            int deltaX = e.X - _lastMousePosition.X;
            int deltaY = e.Y - _lastMousePosition.Y;
            if (Control.ModifierKeys == Keys.Shift) // 按住 Shift 键旋转
                UpdateRotationMatrix(deltaX, deltaY);
            else
            {
                float scale = base.Distance / (base.Distance + _rectangleF3D.Z);
                float deltaX3D = deltaX / scale;
                float deltaY3D = deltaY / scale;
                _rectangleF3D.X += deltaX3D;
                _rectangleF3D.Y += deltaY3D;

            }
            _lastMousePosition = e.Location;
        }
        private bool IsMouseInRect(Point mousePoint) => Bounds.Contains(mousePoint);
        private void ToRectangleF(RectangleF* rectangleF, float distance)
        {
            float minX = _cubePointsPtr->X;
            float minY = _cubePointsPtr->Y;
            float maxX = minX;
            float maxY = minY;
            for (int i = 1; i < _cubePointsPtrSize; i++)
            {
                PointF* p = _cubePointsPtr + i;
                if (p->X < minX) minX = p->X;
                if (p->X > maxX) maxX = p->X;
                if (p->Y < minY) minY = p->Y;
                if (p->Y > maxY) maxY = p->Y;
            }
            rectangleF->X = minX; rectangleF->Y = minY;
            rectangleF->Width = maxX - minX;
            rectangleF->Height = maxY - minY;
        }

        private Matrix4x4 _rotationMatrix = Matrix4x4.Identity;
        private void UpdateRotationMatrix(int deltaX, int deltaY)
        {
            _rotationMatrix *= Matrix4x4.CreateRotationX(deltaY * RotationScale) * Matrix4x4.CreateRotationY(deltaX * RotationScale);
        }
        private Point3D _center = new Point3D();
        private void UpdateCenter()
        {
            _center.X = _rectangleF3D.X + _rectangleF3D.Width / 2;
            _center.Y = _rectangleF3D.Y + _rectangleF3D.Height / 2;
            _center.Z = _rectangleF3D.Z + _rectangleF3D.Depth / 2;
        }
        private static void TransformPoint(Point3D* point, Matrix4x4* matrix)
        {
            float x = point->X;
            float y = point->Y;
            float z = point->Z;
            point->X = x * matrix->M11 + y * matrix->M12 + z * matrix->M13 + matrix->M14;
            point->Y = x * matrix->M21 + y * matrix->M22 + z * matrix->M23 + matrix->M24;
            point->Z = x * matrix->M31 + y * matrix->M32 + z * matrix->M33 + matrix->M34;
        }
        protected override void DisposeUnmanaged()
        {
            FreeT(_point3DPtr);
            FreeT(_cubePointsPtr);
        }
        protected override void DisposeManaged()
        {
        }
        // 定义立方体的边
        static readonly int[,] _edgescube = new int[,]
        {
        {0, 1}, {1, 2}, {2, 3}, {3, 0}, // 底面
        {0, 4}, {4, 5}, {5, 1}, // 从底面到顶面
        {5, 6}, {6, 2}, // 顶面
        {6, 7}, {7, 3}, // 顶面
        {7, 4} // 回到起点
        };
    }
}
